// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2014-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.
#include "Instruction.h"
#include <map>

namespace dev
{
namespace eth
{
// clang-format off
static const std::map<Instruction,  InstructionInfo> c_instructionInfo =
{ //                                                   Args,  Ret,  GasPriceTier
    { Instruction::STOP,         { "STOP",                0,    0,  Tier::Zero } },
    { Instruction::ADD,          { "ADD",                 2,    1,  Tier::VeryLow } },
    { Instruction::SUB,          { "SUB",                 2,    1,  Tier::VeryLow } },
    { Instruction::MUL,          { "MUL",                 2,    1,  Tier::Low } },
    { Instruction::DIV,          { "DIV",                 2,    1,  Tier::Low } },
    { Instruction::SDIV,         { "SDIV",                2,    1,  Tier::Low } },
    { Instruction::MOD,          { "MOD",                 2,    1,  Tier::Low } },
    { Instruction::SMOD,         { "SMOD",                2,    1,  Tier::Low } },
    { Instruction::EXP,          { "EXP",                 2,    1,  Tier::Special } },
    { Instruction::NOT,          { "NOT",                 1,    1,  Tier::VeryLow } },
    { Instruction::LT,           { "LT",                  2,    1,  Tier::VeryLow } },
    { Instruction::GT,           { "GT",                  2,    1,  Tier::VeryLow } },
    { Instruction::SLT,          { "SLT",                 2,    1,  Tier::VeryLow } },
    { Instruction::SGT,          { "SGT",                 2,    1,  Tier::VeryLow } },
    { Instruction::EQ,           { "EQ",                  2,    1,  Tier::VeryLow } },
    { Instruction::ISZERO,       { "ISZERO",              1,    1,  Tier::VeryLow } },
    { Instruction::AND,          { "AND",                 2,    1,  Tier::VeryLow } },
    { Instruction::OR,           { "OR",                  2,    1,  Tier::VeryLow } },
    { Instruction::XOR,          { "XOR",                 2,    1,  Tier::VeryLow } },
    { Instruction::BYTE,         { "BYTE",                2,    1,  Tier::VeryLow } },
    { Instruction::SHL,          { "SHL",                 2,    1,  Tier::VeryLow } },
    { Instruction::SHR,          { "SHR",                 2,    1,  Tier::VeryLow } },
    { Instruction::SAR,          { "SAR",                 2,    1,  Tier::VeryLow } },
    { Instruction::ADDMOD,       { "ADDMOD",              3,    1,  Tier::Mid } },
    { Instruction::MULMOD,       { "MULMOD",              3,    1,  Tier::Mid } },
    { Instruction::SIGNEXTEND,   { "SIGNEXTEND",          2,    1,  Tier::Low } },
    { Instruction::SHA3,         { "SHA3",                2,    1,  Tier::Special } },
    { Instruction::ADDRESS,      { "ADDRESS",             0,    1,  Tier::Base } },
    { Instruction::BALANCE,      { "BALANCE",             1,    1,  Tier::Special } },
    { Instruction::ORIGIN,       { "ORIGIN",              0,    1,  Tier::Base } },
    { Instruction::CALLER,       { "CALLER",              0,    1,  Tier::Base } },
    { Instruction::CALLVALUE,    { "CALLVALUE",           0,    1,  Tier::Base } },
    { Instruction::CALLDATALOAD, { "CALLDATALOAD",        1,    1,  Tier::VeryLow } },
    { Instruction::CALLDATASIZE, { "CALLDATASIZE",        0,    1,  Tier::Base } },
    { Instruction::CALLDATACOPY, { "CALLDATACOPY",        3,    0,  Tier::VeryLow } },
    { Instruction::CODESIZE,     { "CODESIZE",            0,    1,  Tier::Base } },
    { Instruction::CODECOPY,     { "CODECOPY",            3,    0,  Tier::VeryLow } },
    { Instruction::GASPRICE,     { "GASPRICE",            0,    1,  Tier::Base } },
    { Instruction::EXTCODESIZE,  { "EXTCODESIZE",         1,    1,  Tier::Special } },
    { Instruction::EXTCODECOPY,  { "EXTCODECOPY",         4,    0,  Tier::Special } },
    { Instruction::RETURNDATASIZE,{"RETURNDATASIZE",      0,    1,  Tier::Base } },
    { Instruction::RETURNDATACOPY,{"RETURNDATACOPY",      3,    0,  Tier::VeryLow } },
    { Instruction::EXTCODEHASH,  { "EXTCODEHASH",         1,    1,  Tier::Special }},
    { Instruction::BLOCKHASH,    { "BLOCKHASH",           1,    1,  Tier::Special } },
    { Instruction::COINBASE,     { "COINBASE",            0,    1,  Tier::Base } },
    { Instruction::TIMESTAMP,    { "TIMESTAMP",           0,    1,  Tier::Base } },
    { Instruction::NUMBER,       { "NUMBER",              0,    1,  Tier::Base } },
    { Instruction::DIFFICULTY,   { "DIFFICULTY",          0,    1,  Tier::Base } },
    { Instruction::GASLIMIT,     { "GASLIMIT",            0,    1,  Tier::Base } },
    { Instruction::CHAINID,      { "CHAINID",             0,    1,  Tier::Base } },
    { Instruction::SELFBALANCE,  { "SELFBALANCE",         0,    1,  Tier::Low } },   
    { Instruction::POP,          { "POP",                 1,    0,  Tier::Base } },
    { Instruction::MLOAD,        { "MLOAD",               1,    1,  Tier::VeryLow } },
    { Instruction::MSTORE,       { "MSTORE",              2,    0,  Tier::VeryLow } },
    { Instruction::MSTORE8,      { "MSTORE8",             2,    0,  Tier::VeryLow } },
    { Instruction::SLOAD,        { "SLOAD",               1,    1,  Tier::Special } },
    { Instruction::SSTORE,       { "SSTORE",              2,    0,  Tier::Special } },
    { Instruction::JUMP,         { "JUMP",                1,    0,  Tier::Mid } },
    { Instruction::JUMPI,        { "JUMPI",               2,    0,  Tier::High } },
    { Instruction::PC,           { "PC",                  0,    1,  Tier::Base } },
    { Instruction::MSIZE,        { "MSIZE",               0,    1,  Tier::Base } },
    { Instruction::GAS,          { "GAS",                 0,    1,  Tier::Base } },
    { Instruction::JUMPDEST,     { "JUMPDEST",            0,    0,  Tier::Special } },
    { Instruction::PUSH1,        { "PUSH1",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH2,        { "PUSH2",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH3,        { "PUSH3",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH4,        { "PUSH4",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH5,        { "PUSH5",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH6,        { "PUSH6",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH7,        { "PUSH7",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH8,        { "PUSH8",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH9,        { "PUSH9",               0,    1,  Tier::VeryLow } },
    { Instruction::PUSH10,       { "PUSH10",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH11,       { "PUSH11",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH12,       { "PUSH12",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH13,       { "PUSH13",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH14,       { "PUSH14",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH15,       { "PUSH15",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH16,       { "PUSH16",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH17,       { "PUSH17",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH18,       { "PUSH18",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH19,       { "PUSH19",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH20,       { "PUSH20",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH21,       { "PUSH21",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH22,       { "PUSH22",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH23,       { "PUSH23",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH24,       { "PUSH24",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH25,       { "PUSH25",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH26,       { "PUSH26",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH27,       { "PUSH27",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH28,       { "PUSH28",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH29,       { "PUSH29",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH30,       { "PUSH30",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH31,       { "PUSH31",              0,    1,  Tier::VeryLow } },
    { Instruction::PUSH32,       { "PUSH32",              0,    1,  Tier::VeryLow } },
    { Instruction::DUP1,         { "DUP1",                1,    2,  Tier::VeryLow } },
    { Instruction::DUP2,         { "DUP2",                2,    3,  Tier::VeryLow } },
    { Instruction::DUP3,         { "DUP3",                3,    4,  Tier::VeryLow } },
    { Instruction::DUP4,         { "DUP4",                4,    5,  Tier::VeryLow } },
    { Instruction::DUP5,         { "DUP5",                5,    6,  Tier::VeryLow } },
    { Instruction::DUP6,         { "DUP6",                6,    7,  Tier::VeryLow } },
    { Instruction::DUP7,         { "DUP7",                7,    8,  Tier::VeryLow } },
    { Instruction::DUP8,         { "DUP8",                8,    9,  Tier::VeryLow } },
    { Instruction::DUP9,         { "DUP9",                9,   10,  Tier::VeryLow } },
    { Instruction::DUP10,        { "DUP10",              10,   11,  Tier::VeryLow } },
    { Instruction::DUP11,        { "DUP11",              11,   12,  Tier::VeryLow } },
    { Instruction::DUP12,        { "DUP12",              12,   13,  Tier::VeryLow } },
    { Instruction::DUP13,        { "DUP13",              13,   14,  Tier::VeryLow } },
    { Instruction::DUP14,        { "DUP14",              14,   15,  Tier::VeryLow } },
    { Instruction::DUP15,        { "DUP15",              15,   16,  Tier::VeryLow } },
    { Instruction::DUP16,        { "DUP16",              16,   17,  Tier::VeryLow } },
    { Instruction::SWAP1,        { "SWAP1",               2,    2,  Tier::VeryLow } },
    { Instruction::SWAP2,        { "SWAP2",               3,    3,  Tier::VeryLow } },
    { Instruction::SWAP3,        { "SWAP3",               4,    4,  Tier::VeryLow } },
    { Instruction::SWAP4,        { "SWAP4",               5,    5,  Tier::VeryLow } },
    { Instruction::SWAP5,        { "SWAP5",               6,    6,  Tier::VeryLow } },
    { Instruction::SWAP6,        { "SWAP6",               7,    7,  Tier::VeryLow } },
    { Instruction::SWAP7,        { "SWAP7",               8,    8,  Tier::VeryLow } },
    { Instruction::SWAP8,        { "SWAP8",               9,    9,  Tier::VeryLow } },
    { Instruction::SWAP9,        { "SWAP9",              10,   10,  Tier::VeryLow } },
    { Instruction::SWAP10,       { "SWAP10",             11,   11,  Tier::VeryLow } },
    { Instruction::SWAP11,       { "SWAP11",             12,   12,  Tier::VeryLow } },
    { Instruction::SWAP12,       { "SWAP12",             13,   13,  Tier::VeryLow } },
    { Instruction::SWAP13,       { "SWAP13",             14,   14,  Tier::VeryLow } },
    { Instruction::SWAP14,       { "SWAP14",             15,   15,  Tier::VeryLow } },
    { Instruction::SWAP15,       { "SWAP15",             16,   16,  Tier::VeryLow } },
    { Instruction::SWAP16,       { "SWAP16",             17,   17,  Tier::VeryLow } },
    { Instruction::LOG0,         { "LOG0",                2,    0,  Tier::Special } },
    { Instruction::LOG1,         { "LOG1",                3,    0,  Tier::Special } },
    { Instruction::LOG2,         { "LOG2",                4,    0,  Tier::Special } },
    { Instruction::LOG3,         { "LOG3",                5,    0,  Tier::Special } },
    { Instruction::LOG4,         { "LOG4",                6,    0,  Tier::Special } },

    { Instruction::JUMPTO,       { "JUMPTO",              1,    0,  Tier::VeryLow } },
    { Instruction::JUMPIF,       { "JUMPIF",              2,    0,  Tier::Low } },
    { Instruction::JUMPV,        { "JUMPV",               1,    0,  Tier::Mid } },
    { Instruction::JUMPSUB,      { "JUMPSUB",             1,    0,  Tier::Low } },
    { Instruction::JUMPSUBV,     { "JUMPSUBV",            1,    0,  Tier::Mid } },
    { Instruction::BEGINSUB,     { "BEGINSUB",            0,    0,  Tier::Special } },
    { Instruction::BEGINDATA,    { "BEGINDATA",           0,    0,  Tier::Special } },
    { Instruction::RETURNSUB,    { "RETURNSUB",           1,    0,  Tier::Mid } },
    { Instruction::PUTLOCAL,     { "PUTLOCAL",            1,    0,  Tier::VeryLow } },
    { Instruction::GETLOCAL,     { "GETLOCAL",            0,    1,  Tier::VeryLow } },

    { Instruction::XADD,         { "XADD",                0,    0,  Tier::Special } },
    { Instruction::XMUL,         { "XMUL",                2,    1,  Tier::Special } },
    { Instruction::XSUB,         { "XSUB",                2,    1,  Tier::Special } },
    { Instruction::XDIV,         { "XDIV",                2,    1,  Tier::Special } },
    { Instruction::XSDIV,        { "XSDIV",               2,    1,  Tier::Special } },
    { Instruction::XMOD,         { "XMOD",                2,    1,  Tier::Special } },
    { Instruction::XSMOD,        { "XSMOD",               2,    1,  Tier::Special } },
    { Instruction::XLT,          { "XLT",                 2,    1,  Tier::Special } },
    { Instruction::XGT,          { "XGT",                 2,    1,  Tier::Special } },
    { Instruction::XSLT,         { "XSLT",                2,    1,  Tier::Special } },
    { Instruction::XSGT,         { "XSGT",                2,    1,  Tier::Special } },
    { Instruction::XEQ,          { "XEQ",                 2,    1,  Tier::Special } },
    { Instruction::XISZERO,      { "XISZERO",             2,    1,  Tier::Special } },
    { Instruction::XAND,         { "XAND",                1,    1,  Tier::Special } },
    { Instruction::XOOR,         { "XOOR",                2,    1,  Tier::Special } },
    { Instruction::XXOR,         { "XXOR",                2,    1,  Tier::Special } },
    { Instruction::XNOT,         { "XNOT",                2,    1,  Tier::Special } },
    { Instruction::XSHL,         { "XSHL",                2,    1,  Tier::Special } },
    { Instruction::XSHR,         { "XSHR",                2,    1,  Tier::Special } },
    { Instruction::XSAR,         { "XSAR",                2,    1,  Tier::Special } },
    { Instruction::XROL,         { "XROL",                2,    1,  Tier::Special } },
    { Instruction::XROR,         { "XROR",                2,    1,  Tier::Special } },
    { Instruction::XPUSH,        { "XPUSH",               1,    1,  Tier::VeryLow } },
    { Instruction::XMLOAD,       { "XMLOAD",              1,    1,  Tier::VeryLow } },
    { Instruction::XMSTORE,      { "XMSTORE",             2,    0,  Tier::VeryLow } },
    { Instruction::XSLOAD,       { "XSLOAD",              1,    1,  Tier::Special } },
    { Instruction::XSSTORE,      { "XSSTORE",             2,    0,  Tier::Special } },
    { Instruction::XVTOWIDE,     { "XVTOWIDE",            1,    1,  Tier::VeryLow } },
    { Instruction::XWIDETOV,     { "XWIDETOV",            1,    1,  Tier::VeryLow } },
    { Instruction::XPUT,         { "XPUT",                3,    1,  Tier::Special } },
    { Instruction::XGET,         { "XGET",                2,    1,  Tier::Special } },
    { Instruction::XSWIZZLE,     { "XSWIZZLE",            2,    1,  Tier::Special } },
    { Instruction::XSHUFFLE,     { "XSHUFFLE",            3,    1,  Tier::Special } },
    { Instruction::CREATE,       { "CREATE",              3,    1,  Tier::Special } },
    { Instruction::CREATE2,      { "CREATE2",             4,    1,  Tier::Special } },
    { Instruction::CALL,         { "CALL",                7,    1,  Tier::Special } },
    { Instruction::CALLCODE,     { "CALLCODE",            7,    1,  Tier::Special } },
    { Instruction::RETURN,       { "RETURN",              2,    0,  Tier::Zero } },
    { Instruction::STATICCALL,   { "STATICCALL",          6,    1,  Tier::Special } },
    { Instruction::DELEGATECALL, { "DELEGATECALL",        6,    1,  Tier::Special } },
    { Instruction::REVERT,       { "REVERT",              2,    0,  Tier::Special } },
    { Instruction::INVALID,      { "INVALID",             0,    0,  Tier::Zero    } },
    { Instruction::SELFDESTRUCT, { "SELFDESTRUCT",        1,    0,  Tier::Special } },
 
    // these are generated by the interpreter - should never be in user code
    { Instruction::PUSHC,        { "PUSHC",               0,    1, Tier::VeryLow } },
    { Instruction::JUMPC,        { "JUMPC",               1,    0, Tier::Mid } },
    { Instruction::JUMPCI,       { "JUMPCI",              2,    0, Tier::High } },
};
// clang-format on

InstructionInfo instructionInfo(Instruction _inst)
{
    auto it = c_instructionInfo.find(_inst);
    if (it != c_instructionInfo.end())
        return it->second;
    return InstructionInfo{{}, 0, 0, Tier::Invalid};
}


}
}
